package com.newegg.whois.service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.apache.http.HttpHost;
import org.apache.log4j.Logger;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.newegg.whois.util.DateUtil;

@Component
public class ElasticsearchTarget {
	static Logger logger = Logger.getLogger(ElasticsearchTarget.class);
	
	@Value("${elasticsearch.client}")
	String target;
	
	@Value("${elasticsearch.index}")
	String index_patten;
	
	RestHighLevelClient client;
	long count = 0;
	
	List<String> indexs = new ArrayList<>();
	
	@PostConstruct
	public void init() throws IOException{
		String[] hps = target.split(",");
		HttpHost[] hosts = new HttpHost[hps.length];
		for (int i = 0; i < hps.length; i++) {
			String hp = hps[i];
			String[] ipport = hp.split(":");
			hosts[i] = new HttpHost(ipport[0], Integer.parseInt(ipport[1]), "http");
		}
		client = new RestHighLevelClient(RestClient.builder(hosts));
		logger.info("create elasticsearch client");
	}
	
	public synchronized void createIndex(String index) throws IOException{
		GetIndexRequest getIndexRequest = new GetIndexRequest().indices(index);
		if(client.indices().exists(getIndexRequest, RequestOptions.DEFAULT)){ return; }
		CreateIndexRequest indexRequest = new CreateIndexRequest(index);
		indexRequest.settings(
			Settings.builder().put("index.number_of_shards", 5).put("index.number_of_replicas", 1)
		);
		logger.info("create indeces [" + index + "] request");
		
		logger.info("create type [" + index + "] builder");
		XContentBuilder mapBuilder = XContentFactory.jsonBuilder();
		mapBuilder.startObject().startObject(index).startObject("properties");
		
		mapBuilder.startObject("SITE").field("type", "text").endObject();
		mapBuilder.startObject("isIP").field("type", "boolean").endObject();
		mapBuilder.startObject("isDomain").field("type", "boolean").endObject();
		mapBuilder.startObject("IsNewDomain").field("type", "boolean").endObject();
		mapBuilder.startObject("isHostname").field("type", "boolean").endObject();
		mapBuilder.startObject("intranet").field("type", "boolean").endObject();
		mapBuilder.startObject("risk").field("type", "integer").endObject();
		mapBuilder.startObject("Remote_IP").field("type", "text").endObject();
		mapBuilder.startObject("QN").field("type", "text").endObject();
		mapBuilder.startObject("LogType").field("type", "text").endObject();
		mapBuilder.startObject("MachineName").field("type", "text").endObject();
		mapBuilder.startObject("Message").field("type", "text").endObject();
		mapBuilder.startObject("LogTime").field("type", "long").endObject();
		mapBuilder.startObject("LogTimeStamp").field("type", "date").endObject();
		mapBuilder.startObject("updatedDate").field("type", "date").endObject();
		mapBuilder.startObject("creationDate").field("type", "date").endObject();
		mapBuilder.startObject("LastUpdateOfWhoisDatabase").field("type", "date").endObject();
		mapBuilder.startObject("registrarRegistrationExpirationDate").field("type", "date").endObject();
		mapBuilder.startObject("registryExpiryDate").field("type", "date").endObject();
		mapBuilder.startObject("registrarUrl").field("type", "text").endObject();
		mapBuilder.startObject("registrarAbuseContactEmail").field("type", "text").endObject();
		mapBuilder.startObject("Lookup.CNAME").field("type", "text").endObject();
		mapBuilder.startObject("domainName").field("type", "text").endObject();
		mapBuilder.startObject("registrarWhoisServer").field("type", "text").endObject();
		mapBuilder.startObject("nameServer").field("type", "text").endObject();
		mapBuilder.startObject("lastUpdateOfWhoisDatabase").field("type", "text").endObject();
		mapBuilder.startObject("Lookup.IP").field("type", "text").endObject();
		mapBuilder.startObject("Lookup.NS").field("type", "text").endObject();
		mapBuilder.startObject("Lookup.A").field("type", "text").endObject();
		mapBuilder.startObject("Lookup.MX").field("type", "text").endObject();
		mapBuilder.startObject("registrarAbuseContactPhone").field("type", "text").endObject();
		
		mapBuilder.endObject().endObject().endObject();
		indexRequest.mapping(index, mapBuilder);
		client.indices().create(indexRequest, RequestOptions.DEFAULT);
		logger.info("create index [" + index + "] success");
	}
	
	public void importDatas(List<Map<String, Object>> datas) throws Exception {
		BulkRequest bulkRequest = new BulkRequest();
		if( datas==null ) { return; }
		long start_time = System.currentTimeMillis();
		for(Map<String, Object> data : datas) {
			data = fixData(data);
			Date date = (Date) data.get("LogTimeStamp");
			String index = getIndex(index_patten, date);
			if(!indexs.contains(index)){
				createIndex(index);
				indexs.add(index);
			}
			IndexRequest dataRequest = new IndexRequest(index, index);
			dataRequest.source(data);
			bulkRequest.add(dataRequest);
		}
		long fix_data_time = System.currentTimeMillis();
		logger.debug("fix data costs:"+(fix_data_time-start_time));
		try {
			BulkResponse response = client.bulk(bulkRequest, RequestOptions.DEFAULT);
			if(response.hasFailures()){
				logger.error(response.buildFailureMessage());
			}
		} catch (IOException e) {
			throw new RuntimeException("push data to fail", e);
		}
		long send_es_time = System.currentTimeMillis();
		logger.debug("send data to es costs:"+(send_es_time-fix_data_time));
	}
	
	private Map<String, Object> fixData(Map<String, Object> data) {
		Object creationDate = data.get("creationDate");
		Object updatedDate = data.get("updatedDate");
		Object LastUpdateOfWhoisDatabase = data.get("LastUpdateOfWhoisDatabase");
		Object registrarRegistrationExpirationDate = data.get("registrarRegistrationExpirationDate");
		Object registryExpiryDate = data.get("registryExpiryDate");
		Object LogTimeStamp = data.get("LogTimeStamp");
		if(creationDate != null && !"".equals(creationDate)){
			Date date = DateUtil.StringToDate1(creationDate.toString());
			if(date != null){
				long lastMonth = System.currentTimeMillis() - (30 * 24 * 60 * 60 * 1000);
				if(date.getTime() > lastMonth){
					data.put("risk", 1);
					data.put("IsNewDomain", true);
				}else{
					data.put("risk", 0);
					data.put("IsNewDomain", false);
				}
			}
			data.put("creationDate", date);
		}
		if(updatedDate != null && !"".equals(updatedDate)){
			data.put("updatedDate", DateUtil.StringToDate1(updatedDate.toString()));
		}
		if(LastUpdateOfWhoisDatabase != null && !"".equals(LastUpdateOfWhoisDatabase)){
			data.put("LastUpdateOfWhoisDatabase", DateUtil.StringToDate1(LastUpdateOfWhoisDatabase.toString()));
		}
		if(registrarRegistrationExpirationDate != null && !"".equals(registrarRegistrationExpirationDate)){
			data.put("registrarRegistrationExpirationDate", DateUtil.StringToDate1(registrarRegistrationExpirationDate.toString()));
		}
		if(registryExpiryDate != null && !"".equals(registryExpiryDate)){
			data.put("registryExpiryDate", DateUtil.StringToDate1(registryExpiryDate.toString()));
		}
		if(LogTimeStamp != null && !"".equals(LogTimeStamp)){
			if(LogTimeStamp instanceof Date ) {
				Date date = (Date)LogTimeStamp;
				data.put("LogTimeStamp", date);
				data.put("LogTime", date.getTime());
			}else {
				Long date = (Long) LogTimeStamp;
				data.put("LogTimeStamp", new Date(date));
				data.put("LogTime", date);
			}
		}
		
		return data;
	}

	@PreDestroy
	public void destory() throws IOException{
		if(client != null){
			client.close();
		}
	}
	
	static String getIndex(String index_patten, Date date){
		String parseStyle =  index_patten.substring(index_patten.indexOf("{") + 1, index_patten.indexOf("}"));
		return index_patten.substring(0, index_patten.indexOf("{")) + DateUtil.DateToString(date, parseStyle);
	}
	
	public static void main(String[] args) {
		String index_patten = "whois_{yyyyMMdd}";
		System.out.println(getIndex(index_patten, new Date()));
	}
}
